/*
 Copyright (c) 2013 MeherTJ G. All rights reserved.
 License: LGPL for personnal study or free software.
 */

#pragma once

#include <cmath>
#include <type_traits>

#define ZEN_F_EPSILON 2e-08
#define ZEN_F_PI 3.1415926535897932384626433832795
#define ZEN_F_2PI 6.283185307179586476925286766559
#define ZEN_F_PI2 1.5707963267948966192313216916398
#define ZEN_F_PI4 0.78539816339744830961566084581988
#define ZEN_F_SQRT_2 1.4142135623730950488016887242097
#define ZEN_F_SQRT_3 1.7320508075688772935274463415059
#define ZEN_F_SQRT_5 2.2360679774997896964091736687313

namespace Zen
{
	namespace Number
	{
		/// v*v
		template <typename Type>
		inline Type Square(Type value)
		{
			return value * value;
		}

		/// v*v*v
		template <typename Type>
		inline Type Cube(Type value)
		{
			return value * value * value;
		}

		/// =~= 0
		template <typename _FloatType>
		inline bool IsFuzzyZero(_FloatType num, _FloatType var = ZEN_F_EPSILON)
		{
			return num < var && num > -var;
		}

		/// A =~= B
		template <typename _FloatType>
		inline bool IsFuzzyEqual(_FloatType num0, _FloatType num1, _FloatType var = ZEN_F_EPSILON)
		{
			return IsFuzzyZero(num0 - num1, var);
		}
		/// gcd
		template <typename Type>
		inline Type GetGCD(Type n, Type m)
		{
			if (m == 0 || n == 0) return 1;
			do {
				auto t = n % m;
				n = m;
				m = t;
			} while (m);
			return n;
		}

		namespace _
		{
			/// MinPower2
			template <typename _Int, size_t byte_>
			struct MinPower2NoLessC
			{
			};

			template <typename _Int>
			struct MinPower2NoLessC<_Int, 1>
			{
				static inline _Int Get(_Int i)
				{
					auto v = uint16_t(i) - 1;
					v |= v >> 1;
					v |= v >> 2;
					v |= v >> 4;
					return (_Int)(++v);
				}
			};

			template <typename _Int>
			struct MinPower2NoLessC<_Int, 2>
			{
				static inline _Int Get(_Int i)
				{
					auto v = uint16_t(i) - 1;
					v |= v >> 1;
					v |= v >> 2;
					v |= v >> 4;
					v |= v >> 8;
					return (_Int)(++v);
				}
			};
			template <typename _Int>
			struct MinPower2NoLessC<_Int, 4>
			{
				static inline _Int Get(_Int i)
				{
					auto v = uint32_t(i) - 1;
					v |= v >> 1;
					v |= v >> 2;
					v |= v >> 4;
					v |= v >> 8;
					v |= v >> 16;
					return (_Int)(++v);
				}
			};
			template <typename _Int>
			struct MinPower2NoLessC<_Int, 8>
			{
				static inline _Int Get(_Int i)
				{
					auto v = uint64_t(i) - 1;
					v |= v >> 1;
					v |= v >> 2;
					v |= v >> 4;
					v |= v >> 8;
					v |= v >> 16;
					v |= v >> 32;
					return (_Int)(++v);
				}
			};
		} // namespace _

		//minimum 2th power number that >= i.
		template <typename _Int>
		inline _Int MinPower2NoLess(_Int i)
		{
			return _::MinPower2NoLessC<_Int, sizeof(_Int)>::Get(i);
		}

		/// (0, 1) >>> (A, B)
		template <typename _FloatType>
		inline _FloatType Lerp(_FloatType start, _FloatType end, _FloatType v)
		{
			return start + (end - start) * v;
		}

		template <typename _Float>
		inline _Float LerpDown(_Float start, _Float end, _Float v)
		{
			auto v1 = 1.f - v;
			return start + (end - start) * (1.f - (v1 * v1));
		}

		template <typename _Float>
		inline _Float LerpUp(_Float start, _Float end, _Float v)
		{
			return start + (end - start) * (v * v);
		}
	} // namespace Number
} // namespace Zen
